package Cache;

import java.util.GregorianCalendar;

import fr.zadoka.zadokadna.Util.BitmapUtil;
import fr.zadoka.zadokadna.Util.CalendarUtil;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.util.LruCache;


public class ZadokaImageCache implements ImageCache {
	
    private static final String TAG = "fr.zadoka.zadokadna.ImageCache";
	
	private LruCache<String, Bitmap> mMemoryCache;
	
	private ZadokaImageCache()
	{
	    // Get max available VM memory, exceeding this amount will throw an
	    // OutOfMemory exception. Stored in kilobytes as LruCache takes an
	    // int in its constructor.
	    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

	    // Use 1/8th of the available memory for this memory cache.
	    final int cacheSize = maxMemory / 8;

	    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
	        protected int sizeOf(String key, Bitmap bitmap) {
	            // The cache size will be measured in kilobytes rather than
	            // number of items.
	            return BitmapUtil.getByteCount(bitmap) / 1024;
	        }
	    };		
	}
	
	 public static ZadokaImageCache getInstance(FragmentManager fragmentManager) {

	        // Search for, or create an instance of the non-UI RetainFragment
	        final RetainFragment mRetainFragment = findOrCreateRetainFragment(fragmentManager);

	        // See if we already have an ImageCache stored in RetainFragment
	        ZadokaImageCache imageCache = (ZadokaImageCache) mRetainFragment.getObject();

	        // No existing ImageCache, create one and store it in RetainFragment
	        if (imageCache == null) {
	            imageCache = new ZadokaImageCache();
	            mRetainFragment.setObject(imageCache);
	        }

	        return imageCache;
	    }	
	
	public void addBitmapToMemoryCache(GregorianCalendar key, Bitmap bitmap) {
	    if (getBitmapFromMemCache(key) == null) {
	    	
	        mMemoryCache.put(FormatDateToString(key), bitmap);
	    }
	}

	private String FormatDateToString(GregorianCalendar key) {
		return CalendarUtil.GregorianCalendarToString(key);
	}

	public Bitmap getBitmapFromMemCache(GregorianCalendar key) {
	    return mMemoryCache.get(FormatDateToString(key));
	}	
	
    private static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {
        //BEGIN_INCLUDE(find_create_retain_fragment)
        // Check to see if we have retained the worker fragment.
        RetainFragment mRetainFragment = (RetainFragment) fm.findFragmentByTag(TAG);

        // If not retained (or first time running), we need to create and add it.
        if (mRetainFragment == null) {
            mRetainFragment = new RetainFragment();
            fm.beginTransaction().add(mRetainFragment, TAG).commitAllowingStateLoss();
        }

        return mRetainFragment;
        //END_INCLUDE(find_create_retain_fragment)
    }

    /**
     * A simple non-UI Fragment that stores a single Object and is retained over configuration
     * changes. It will be used to retain the ImageCache object.
     */
    public static class RetainFragment extends Fragment {
        private Object mObject;

        /**
         * Empty constructor as per the Fragment documentation
         */
        public RetainFragment() {}

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            // Make sure this Fragment is retained over a configuration change
            setRetainInstance(true);
        }

        /**
         * Store a single object in this Fragment.
         *
         * @param object The object to store
         */
        public void setObject(Object object) {
            mObject = object;
        }

        /**
         * Get the stored object.
         *
         * @return The stored object
         */
        public Object getObject() {
            return mObject;
        }
    }
	
}
